//run omp & sequential solver
//$Id: run_omp.h 175 2009-09-12 17:34:23Z Oleg.Bulychov $
#pragma once
#ifndef RUN_OMP_H
#define RUN_OMP_H

#include "src/heo/include/ini_file.h"
#include "src/heo/include/fast_stream.h"
#include "src/heo/include/stream_visitor.h"
#include "src/heo/include/config.h"

template<class T>
struct Run_OMP
{
    typedef T                           TSolver;
    typedef typename TSolver::TProblem  TProblem;
    typedef typename TSolver::TSolution TSolution;
    typedef typename TSolver::TConfig   TConfig;
    int retval;

    int run(int argc, char* argv[], char const* szName)
    {
        using namespace std;

        setlocale(LC_ALL, "C");//:decimal point must be '.'

        if (argc != 2)
        {
            cout << "usage: " << szName << " file.ini" << endl;
            return 0;
        }

#if defined(_OPENMP)
        cout << "omp processors available: " << omp_get_num_procs() << lf;
#pragma omp parallel
        {
#pragma omp critical
            cout << "thread: " << omp_get_thread_num() << " from " << omp_get_num_threads() << lf;
        }
#else
        cout << "Sequential version" << lf;
#endif

        TConfig cfg;
        ini::in ini(argv[1]);
        ini.load(cfg, szName);
        cout << "[" << szName << "]" << lf;
        meta::ostream_visitor kcout(cout);
        kcout << cfg;
        cout << endl;
        if (ini.load_Error())
            ini::out(argv[1]).save(cfg, szName);

        uniform_random::randomize(omp_get_max_threads(), cfg.rand_seed_);

        TProblem problem;
        //root_profiler.enter();
        {
            vector<char> buffer;
            {
                //KProfiler pr("loading");
                ifstream in(cfg.input_file_.c_str());
                if (!in)
                {
                    cout << "ERROR: '" << cfg.input_file_ << "' not found" << endl;
                    return 0;
                }
                in.seekg(0, ios::end);
                streamsize length = in.tellg();
                in.seekg(0, ios::beg);
                buffer.resize(length);
                if (length <= 0)
                {
                    cout << "ERROR: '" << cfg.input_file_ << "' is empty" << endl;
                    return 0;
                }
                in.read(&buffer[0], length);
            }
            fast_istream iss(&buffer[0], buffer.size());//:not copied!
            //KProfiler pr("parsing");
            if (!problem.read(iss))
            {
                cout << "ERROR: '" << cfg.input_file_ << "' corrupted" << endl;
                return 0;
            }
        }

        TSolution sol;
        sol.init(problem, cfg);
        sol.generate_Trivial();

        double start_time = omp_get_wtime();
        TSolver::solve(problem, sol, cfg);
        double end_time = omp_get_wtime();

        cout << "time = " << end_time - start_time << " s" << lf
            << "solution:" << lf;
        sol.print(cout, problem, cfg);
        return 0;
    }

    Run_OMP(int argc, char* argv[], char const* szName)
    {
        retval = run(argc, argv, szName);
#if defined(_MSC_VER)
        extern void If_Debug_Press_Enter();
        If_Debug_Press_Enter();
#endif
    }
};

#endif
//EOF!
